#ifndef __GLF_FILESTREAM_H_INCLUDED__
#define __GLF_FILESTREAM_H_INCLUDED__

#include <glf/config.h>

#if GLF_VIRTUAL_FILESTREAM

#include <glf/io/fileStreamImpl.h>
#include <string>

namespace glf {

class FileStream : public IOStream {

public:

	friend class FileStreamMgr;
	friend struct ReadASyncThread;

	FileStream();
	FileStream(const char* filename, ios::openflag flag = ios::read | ios::loc_data);
	virtual ~FileStream();

	bool Open(const char* filename, ios::openflag flag = ios::read | ios::loc_data);
	virtual void Close();

	virtual size_t GetSize() const;

	virtual bool Seek(int offset, ios::seek origin);
	virtual size_t Peek(void* buffer, size_t size);
	bool CancelAsync(FileStreamImpl::Callback callback, void* arg);
	
	virtual bool CanSeek() const;
	virtual bool CanRead  () const;
	virtual bool CanWrite () const;

	int WaitASync(size_t ms) const;

	virtual size_t Tell()  const;
	
	bool IsEof() const;
	bool IsOpened() const;
	bool IsBusy() const;

	virtual size_t Read(void* buffer, size_t size);

	virtual size_t ReadWithOffset(void* buffer, size_t size, size_t offset);
	virtual bool ReadASync(void* buffer, size_t size, size_t offset, FileStreamImpl::Callback callback, void* arg);
	virtual size_t Write(const void* buffer, size_t size);

	ios::openflag CopyPath(char* dst, size_t len) const;
	const char* GetPath(ios::openflag& loc) const;
	const char* GetFilename() const;

	static void DispatchDoneReads();

private:

	bool OpenImpl(const char* filename, ios::openflag flag);
	void CloseImpl();
	void FileOut();
	void FileIn();

	void Check();

	uint64 GetCounter() const;

	FileStreamImpl mFileStream;
	size_t mSize;
	stringc mFilename;
	ios::openflag mFlag;
	size_t mOffset;

	uint64 mCounter;

	enum Status
	{
		STATUS_ERROR,
		STATUS_OPENED,
		STATUS_CLOSED,
		STATUS_OUT
	};

	Status mStatus;
};

} // end namespace glf

#else // GLF_VIRTUAL_FILESTREAM

#include <glf/io/fileStreamImpl.h>

namespace glf {

// use of derived class instead of typedef since typedef is not friendly with forward declaration
class FileStream : public FileStreamImpl
{
public:
	FileStream()
	{
	}

	FileStream(const char* filename, ios::openflag flag = ios::read | ios::loc_data)
		: FileStreamImpl(filename, flag)
	{
	}
};

} // end namespace glf

#endif // GLF_VIRTUAL_FILESTREAM
#endif // __GLF_FILESTREAM_H_INCLUDED__
